#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Alert Management System
Handles generation, dispatch and logging of alerts
"""

import logging
import time
import json
import threading
from typing import Dict, List, Any, Optional
from datetime import datetime

logger = logging.getLogger("video_processing.alert_manager")

class AlertManager:
    """Alert Management Class"""
    
    def __init__(self):
        """Initialize alert manager"""
        self.alert_configs = {}
        self.active_alerts = {}
        self.alert_history = []
        self.max_history_size = 1000
        self.alert_dispatch_lock = threading.Lock()
        self.alert_counter = 0
        logger.info("Alert manager initialized")
    
    def set_alert_config(self, camera_id: str, config: Dict[str, Any]):
        """Set alert configuration for specific camera
        
        Args:
            camera_id: Camera identifier
            config: Alert configuration settings
        """
        self.alert_configs[camera_id] = config
        logger.info(f"Set alert configuration for camera {camera_id}")
    
    def process_violations(self, camera_id: str, violations: List[Dict], frame_info: Dict = None) -> List[Dict]:
        """Process detected violations and generate alerts
        
        Args:
            camera_id: Camera identifier
            violations: List of detected violations
            frame_info: Additional frame information
            
        Returns:
            List of generated alerts
        """
        try:
            # Initialize camera configuration if not exists
            if camera_id not in self.alert_configs:
                self.alert_configs[camera_id] = self._get_default_config()
            
            config = self.alert_configs[camera_id]
            generated_alerts = []
            
            for violation in violations:
                # Check if this violation type is enabled
                if not self._is_violation_type_enabled(violation['type'], config):
                    continue
                
                # Create alert
                alert = self._create_alert(camera_id, violation, frame_info)
                
                # Check if alert should be dispatched based on priority
                if self._should_dispatch_alert(alert, config):
                    with self.alert_dispatch_lock:
                        # Generate unique alert ID
                        alert_id = self._generate_alert_id()
                        alert['alert_id'] = alert_id
                        
                        # Store active alert
                        self.active_alerts[alert_id] = alert
                        
                        # Add to history
                        self._add_to_history(alert)
                        
                        # Dispatch alert
                        self._dispatch_alert(alert, config)
                        
                        generated_alerts.append(alert)
            
            # Clean up inactive alerts
            self._cleanup_inactive_alerts()
            
            return generated_alerts
            
        except Exception as e:
            logger.error(f"Error processing violations for camera {camera_id}: {str(e)}")
            return []
    
    def _create_alert(self, camera_id: str, violation: Dict, frame_info: Optional[Dict] = None) -> Dict:
        """Create alert from violation data"""
        alert = {
            'camera_id': camera_id,
            'violation_type': violation['type'],
            'object_id': violation['object_id'],
            'object_class': violation['object_class'],
            'message': violation['message'],
            'timestamp': violation['timestamp'],
            'status': 'active',
            'priority': self._determine_priority(violation['type']),
            'created_at': datetime.now().isoformat()
        }
        
        # Add frame information if available
        if frame_info:
            alert['frame_info'] = frame_info
        
        return alert
    
    def _determine_priority(self, violation_type: str) -> str:
        """Determine alert priority based on violation type"""
        priority_map = {
            'red_light_violation': 'high',
            'restricted_area_violation': 'high',
            'vehicle_restricted_area_violation': 'high',
            'loitering_violation': 'medium'
        }
        
        return priority_map.get(violation_type, 'low')
    
    def _is_violation_type_enabled(self, violation_type: str, config: Dict) -> bool:
        """Check if specific violation type is enabled for alerts"""
        enabled_violations = config.get('enabled_violations', ['all'])
        
        if 'all' in enabled_violations:
            return True
        
        return violation_type in enabled_violations
    
    def _should_dispatch_alert(self, alert: Dict, config: Dict) -> bool:
        """Check if alert should be dispatched based on configuration"""
        # Check priority thresholds
        min_priority = config.get('min_priority', 'low')
        priority_levels = {'low': 0, 'medium': 1, 'high': 2}
        
        if priority_levels[alert['priority']] < priority_levels[min_priority]:
            return False
        
        # Check for duplicate alerts
        duplicate_window = config.get('duplicate_window_seconds', 60)
        current_time = time.time()
        
        # Check recent history for duplicates
        for recent_alert in self.alert_history:
            if (recent_alert['camera_id'] == alert['camera_id'] and
                recent_alert['violation_type'] == alert['violation_type'] and
                recent_alert['object_id'] == alert['object_id'] and
                current_time - recent_alert['timestamp'] < duplicate_window):
                return False
        
        return True
    
    def _dispatch_alert(self, alert: Dict, config: Dict):
        """Dispatch alert through configured channels"""
        dispatch_channels = config.get('dispatch_channels', ['log'])
        
        for channel in dispatch_channels:
            try:
                if channel == 'log':
                    self._dispatch_log_alert(alert)
                elif channel == 'email':
                    self._dispatch_email_alert(alert, config.get('email_config', {}))
                elif channel == 'sms':
                    self._dispatch_sms_alert(alert, config.get('sms_config', {}))
                elif channel == 'webhook':
                    self._dispatch_webhook_alert(alert, config.get('webhook_config', {}))
                else:
                    logger.warning(f"Unknown dispatch channel: {channel}")
            except Exception as e:
                logger.error(f"Error dispatching alert to channel {channel}: {str(e)}")
    
    def _dispatch_log_alert(self, alert: Dict):
        """Dispatch alert to log"""
        priority_emoji = {
            'high': '🔴',
            'medium': '🟠',
            'low': '🟢'
        }
        
        emoji = priority_emoji.get(alert['priority'], '⚪')
        logger.info(f"{emoji} ALERT [{alert['alert_id']}] {alert['camera_id']}: {alert['message']}")
    
    def _dispatch_email_alert(self, alert: Dict, email_config: Dict):
        """Dispatch alert via email (simulation)"""
        # This is a simulation - in real implementation, use email library
        recipients = email_config.get('recipients', [])
        if recipients:
            logger.info(f"Simulating email alert to {recipients}: {alert['message']}")
    
    def _dispatch_sms_alert(self, alert: Dict, sms_config: Dict):
        """Dispatch alert via SMS (simulation)"""
        # This is a simulation - in real implementation, use SMS gateway API
        phone_numbers = sms_config.get('phone_numbers', [])
        if phone_numbers:
            logger.info(f"Simulating SMS alert to {phone_numbers}: {alert['message']}")
    
    def _dispatch_webhook_alert(self, alert: Dict, webhook_config: Dict):
        """Dispatch alert via webhook (simulation)"""
        # This is a simulation - in real implementation, use requests library
        webhook_url = webhook_config.get('url', '')
        if webhook_url:
            logger.info(f"Simulating webhook alert to {webhook_url}: {alert['message']}")
    
    def _generate_alert_id(self) -> str:
        """Generate unique alert ID"""
        self.alert_counter += 1
        timestamp = int(time.time() * 1000)
        return f"ALERT_{timestamp}_{self.alert_counter:04d}"
    
    def _add_to_history(self, alert: Dict):
        """Add alert to history and maintain size limit"""
        self.alert_history.append(alert)
        
        # Keep only the most recent alerts
        if len(self.alert_history) > self.max_history_size:
            self.alert_history = self.alert_history[-self.max_history_size:]
    
    def _cleanup_inactive_alerts(self):
        """Clean up inactive alerts"""
        active_timeout = 300  # 5 minutes
        current_time = time.time()
        
        to_remove = []
        for alert_id, alert in self.active_alerts.items():
            if current_time - alert['timestamp'] > active_timeout:
                alert['status'] = 'inactive'
                to_remove.append(alert_id)
        
        for alert_id in to_remove:
            del self.active_alerts[alert_id]
    
    def _get_default_config(self) -> Dict[str, Any]:
        """Get default alert configuration"""
        return {
            'enabled_violations': ['all'],
            'min_priority': 'low',
            'dispatch_channels': ['log'],
            'duplicate_window_seconds': 60,
            'email_config': {
                'recipients': []
            },
            'sms_config': {
                'phone_numbers': []
            },
            'webhook_config': {
                'url': ''
            }
        }
    
    def acknowledge_alert(self, alert_id: str) -> bool:
        """Acknowledge an alert
        
        Args:
            alert_id: Alert identifier
            
        Returns:
            True if alert was acknowledged, False otherwise
        """
        try:
            if alert_id in self.active_alerts:
                self.active_alerts[alert_id]['status'] = 'acknowledged'
                self.active_alerts[alert_id]['acknowledged_at'] = datetime.now().isoformat()
                logger.info(f"Alert {alert_id} acknowledged")
                return True
            
            # Check history
            for alert in self.alert_history:
                if alert['alert_id'] == alert_id and alert['status'] == 'active':
                    alert['status'] = 'acknowledged'
                    alert['acknowledged_at'] = datetime.now().isoformat()
                    logger.info(f"Alert {alert_id} acknowledged from history")
                    return True
            
            logger.warning(f"Alert {alert_id} not found for acknowledgment")
            return False
            
        except Exception as e:
            logger.error(f"Error acknowledging alert {alert_id}: {str(e)}")
            return False
    
    def resolve_alert(self, alert_id: str) -> bool:
        """Resolve an alert
        
        Args:
            alert_id: Alert identifier
            
        Returns:
            True if alert was resolved, False otherwise
        """
        try:
            if alert_id in self.active_alerts:
                self.active_alerts[alert_id]['status'] = 'resolved'
                self.active_alerts[alert_id]['resolved_at'] = datetime.now().isoformat()
                del self.active_alerts[alert_id]
                logger.info(f"Alert {alert_id} resolved")
                return True
            
            # Check history
            for alert in self.alert_history:
                if alert['alert_id'] == alert_id and alert['status'] != 'resolved':
                    alert['status'] = 'resolved'
                    alert['resolved_at'] = datetime.now().isoformat()
                    logger.info(f"Alert {alert_id} resolved from history")
                    return True
            
            logger.warning(f"Alert {alert_id} not found for resolution")
            return False
            
        except Exception as e:
            logger.error(f"Error resolving alert {alert_id}: {str(e)}")
            return False
    
    def get_active_alerts(self, camera_id: str = None) -> List[Dict]:
        """Get active alerts
        
        Args:
            camera_id: Optional camera filter
            
        Returns:
            List of active alerts
        """
        alerts = list(self.active_alerts.values())
        
        if camera_id:
            alerts = [alert for alert in alerts if alert['camera_id'] == camera_id]
        
        # Sort by timestamp (newest first)
        alerts.sort(key=lambda x: x['timestamp'], reverse=True)
        
        return alerts
    
    def get_alert_statistics(self, time_window: int = 3600) -> Dict[str, Any]:
        """Get alert statistics
        
        Args:
            time_window: Time window in seconds
            
        Returns:
            Alert statistics
        """
        current_time = time.time()
        window_start = current_time - time_window
        
        # Filter alerts in time window
        recent_alerts = [
            alert for alert in self.alert_history 
            if alert['timestamp'] >= window_start
        ]
        
        # Count by priority
        priority_counts = {'low': 0, 'medium': 0, 'high': 0}
        # Count by violation type
        type_counts = {}
        # Count by camera
        camera_counts = {}
        
        for alert in recent_alerts:
            # Count by priority
            if alert['priority'] in priority_counts:
                priority_counts[alert['priority']] += 1
            
            # Count by violation type
            violation_type = alert['violation_type']
            if violation_type not in type_counts:
                type_counts[violation_type] = 0
            type_counts[violation_type] += 1
            
            # Count by camera
            camera_id = alert['camera_id']
            if camera_id not in camera_counts:
                camera_counts[camera_id] = 0
            camera_counts[camera_id] += 1
        
        return {
            'total_alerts': len(recent_alerts),
            'active_alerts': len(self.active_alerts),
            'priority_counts': priority_counts,
            'type_counts': type_counts,
            'camera_counts': camera_counts,
            'time_window_seconds': time_window,
            'window_start_time': window_start,
            'window_end_time': current_time
        }

# Create singleton instance for easy import
def get_alert_manager() -> AlertManager:
    """Get alert manager instance
    
    Returns:
        AlertManager instance
    """
    if not hasattr(get_alert_manager, '_instance'):
        get_alert_manager._instance = AlertManager()
    return get_alert_manager._instance